#include "DXUT.h"
#include "Helper.h"

#include <vector>

using namespace std;

#include "Skybox.h"

const D3D11_INPUT_ELEMENT_DESC g_aVertexLayout[] =
{
    { "POSITION",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
const D3D11_INPUT_ELEMENT_DESC g_bVertexLayout[] =
{
    { "POSITION",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD",  0, DXGI_FORMAT_R32G32_FLOAT,    0, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
const D3D11_INPUT_ELEMENT_DESC g_cVertexLayout[] =
{
    { "POSITION",  0, DXGI_FORMAT_R32G32B32_FLOAT,		 0, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_VERTEX_DATA,		0 },
	{ "TEXCOORD",  0, DXGI_FORMAT_R32G32_FLOAT,			 0, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_VERTEX_DATA,		0 },
	{ "INSTANCE",  0, DXGI_FORMAT_R32G32B32A32_FLOAT,    1, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_INSTANCE_DATA,	1 },
	{ "INSTANCE",  1, DXGI_FORMAT_R32G32B32A32_FLOAT,    1, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_INSTANCE_DATA,	1 },
	{ "INSTANCE",  2, DXGI_FORMAT_R32G32B32A32_FLOAT,    1, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_INSTANCE_DATA,	1 },
	{ "INSTANCE",  3, DXGI_FORMAT_R32G32B32A32_FLOAT,    1, D3D11_APPEND_ALIGNED_ELEMENT,  D3D11_INPUT_PER_INSTANCE_DATA,	1 },
};

Skybox::Skybox()
{
    m_pVertexLayout = NULL;
	m_pVertexLayoutTextured = NULL;
	m_pVertexLayoutInstanced = NULL;

	m_pTextureRVGlow = NULL;
	m_pTextureRVColor = NULL;
	m_pTextureRVSun = NULL;
	m_pTextureRVStar = NULL;
}

Skybox::~Skybox()
{
	OnD3D11DestroyDevice();
}

HRESULT Skybox::OnD3D11CreateDevice( ID3D11Device* pd3dDevice)
{
    HRESULT hr = S_OK;
	
	m_pd3dDevice = pd3dDevice;

	D3DX11CreateShaderResourceViewFromFile( pd3dDevice, L"Textures/glow.png", NULL, NULL, &m_pTextureRVGlow, NULL );
	D3DX11CreateShaderResourceViewFromFile( pd3dDevice, L"Textures/sky.png", NULL, NULL, &m_pTextureRVColor, NULL );
	D3DX11CreateShaderResourceViewFromFile( pd3dDevice, L"Textures/sun.png", NULL, NULL, &m_pTextureRVSun, NULL );
	D3DX11CreateShaderResourceViewFromFile( pd3dDevice, L"Textures/starglow.png", NULL, NULL, &m_pTextureRVStar, NULL );

	ID3DBlob* pVSBlob = NULL;
	hr = CompileShaderFromFile( L"BasicShader.fx", "VSky", "vs_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pSkyVertexShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}
	// Create the input layout
	hr = pd3dDevice->CreateInputLayout( g_aVertexLayout, ARRAYSIZE( g_aVertexLayout ), pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &m_pVertexLayout );
	pVSBlob->Release();

	hr = CompileShaderFromFile( L"BasicShader.fx", "PSky", "ps_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreatePixelShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pSkyPixelShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}

	hr = CompileShaderFromFile( L"BasicShader.fx", "VST", "vs_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pSunVertexShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}
	// Create the input layout
	hr = pd3dDevice->CreateInputLayout( g_bVertexLayout, ARRAYSIZE( g_bVertexLayout ), pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &m_pVertexLayoutTextured );
	pVSBlob->Release();

	hr = CompileShaderFromFile( L"BasicShader.fx", "PST", "ps_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreatePixelShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pSunPixelShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}


	hr = CompileShaderFromFile( L"BasicShader.fx", "VStar", "vs_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pStarVertexShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}
	// Create the input layout
	hr = pd3dDevice->CreateInputLayout( g_cVertexLayout, ARRAYSIZE( g_cVertexLayout ), pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &m_pVertexLayoutInstanced);
	pVSBlob->Release();

	hr = CompileShaderFromFile( L"BasicShader.fx", "PStar", "ps_4_0", &pVSBlob );
	if( FAILED( hr ) )
	{
		MessageBox( NULL,
			L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
		return hr;
	}
	hr = pd3dDevice->CreatePixelShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pStarPixelShader );
	if( FAILED( hr ) )
	{	
		SAFE_RELEASE(pVSBlob);
		return hr;
	}

	/* Constant Buffer */
	D3D11_BUFFER_DESC cbDesc;
	ZeroMemory( &cbDesc, sizeof(cbDesc) );

	cbDesc.Usage			= D3D11_USAGE_DEFAULT;
	cbDesc.BindFlags		= D3D11_BIND_CONSTANT_BUFFER;
	cbDesc.CPUAccessFlags	= 0;
	cbDesc.ByteWidth		= sizeof( CB_VS_PER_FRAME );
	pd3dDevice->CreateBuffer( &cbDesc, NULL, &m_pcbVSPerFrame11 );

	cbDesc.Usage			= D3D11_USAGE_DEFAULT;
	cbDesc.BindFlags		= D3D11_BIND_CONSTANT_BUFFER;
	cbDesc.CPUAccessFlags	= 0;
	cbDesc.ByteWidth		= sizeof( CB_PS_PER_FRAME );
	pd3dDevice->CreateBuffer( &cbDesc, NULL, &m_pcbPSPerFrame11 );

	cbDesc.Usage			= D3D11_USAGE_DYNAMIC;
	cbDesc.BindFlags		= D3D11_BIND_CONSTANT_BUFFER;
	cbDesc.CPUAccessFlags	= D3D10_CPU_ACCESS_WRITE;
	cbDesc.ByteWidth		= sizeof( CB_VS_PER_OBJECT );
	pd3dDevice->CreateBuffer( &cbDesc, NULL, &m_pcbVSPerObject11 );
	/* Constant Buffer */

	/* Blend States */
	D3D11_BLEND_DESC BDesc;
	ZeroMemory( &BDesc, sizeof( D3D11_BLEND_DESC ) );
	BDesc.RenderTarget[0].BlendEnable		= TRUE;
	BDesc.RenderTarget[0].SrcBlend			= D3D11_BLEND_SRC_ALPHA;
	BDesc.RenderTarget[0].DestBlend			= D3D11_BLEND_INV_SRC_ALPHA;
	BDesc.RenderTarget[0].BlendOp			= D3D11_BLEND_OP_ADD;
	BDesc.RenderTarget[0].SrcBlendAlpha		= D3D11_BLEND_ONE;
	BDesc.RenderTarget[0].DestBlendAlpha	= D3D11_BLEND_ZERO;
	BDesc.RenderTarget[0].BlendOpAlpha		= D3D11_BLEND_OP_ADD;
	BDesc.RenderTarget[0].RenderTargetWriteMask = 0x0f;
	pd3dDevice->CreateBlendState( &BDesc, &m_pBlendState11 );
	/* Blend States */

	/* Sampler States */
	D3D11_SAMPLER_DESC SSDesc;
	ZeroMemory( &SSDesc, sizeof( D3D11_SAMPLER_DESC ) );
	SSDesc.Filter			= D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	SSDesc.AddressU			= D3D11_TEXTURE_ADDRESS_CLAMP;
	SSDesc.AddressV			= D3D11_TEXTURE_ADDRESS_CLAMP;
	SSDesc.AddressW			= D3D11_TEXTURE_ADDRESS_CLAMP;
	SSDesc.ComparisonFunc	= D3D11_COMPARISON_NEVER;
	SSDesc.MaxAnisotropy	= 0;
	SSDesc.MinLOD			= 0;
	SSDesc.MaxLOD			= D3D11_FLOAT32_MAX;
	if ( pd3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3 ) {
		SSDesc.Filter		= D3D11_FILTER_MIN_MAG_MIP_POINT;
		SSDesc.MaxAnisotropy = 0;
	}
	pd3dDevice->CreateSamplerState( &SSDesc, &m_pSamplerState11 );
	/* Sampler States */

	/* Stencil States */
	D3D11_DEPTH_STENCIL_DESC DSDesc;
	ZeroMemory( &DSDesc, sizeof( D3D11_DEPTH_STENCIL_DESC ) );
	DSDesc.DepthEnable			= FALSE;
	DSDesc.DepthWriteMask		= D3D11_DEPTH_WRITE_MASK_ALL;
	DSDesc.DepthFunc			= D3D11_COMPARISON_LESS;
	DSDesc.StencilEnable		= FALSE;
	DSDesc.StencilReadMask		= D3D11_DEFAULT_STENCIL_READ_MASK;
	DSDesc.StencilWriteMask		= D3D11_DEFAULT_STENCIL_WRITE_MASK;
	DSDesc.FrontFace.StencilFunc= D3D11_COMPARISON_ALWAYS;
	DSDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
	DSDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
	DSDesc.BackFace.StencilDepthFailOp	= D3D11_STENCIL_OP_KEEP;
	DSDesc.FrontFace.StencilPassOp		= D3D11_STENCIL_OP_KEEP;
	DSDesc.BackFace.StencilPassOp		= D3D11_STENCIL_OP_KEEP;
	DSDesc.FrontFace.StencilFailOp		= D3D11_STENCIL_OP_KEEP;
	DSDesc.BackFace.StencilFailOp		= D3D11_STENCIL_OP_KEEP;
	pd3dDevice->CreateDepthStencilState( &DSDesc, &m_pDepthStencilState11 );
	/* Stencil States */

	generateSkyDome(pd3dDevice);
	return hr;
}

void Skybox::generateSkyDome(ID3D11Device* pd3dDevice) {
	vector<D3DXVECTOR3> vbl;
	vector<WORD>		ibl;

	float radius = 1.0f;
	int rings = 20; 
	int sectors = 20;

	float const R = 1./(float)(rings-1);
    float const S = 1./(float)(sectors-1);
    int r, s;

        vbl.resize(rings * sectors * 3);
        //sphere_normals.resize(rings * sectors * 3);
       // sphere_texcoords.resize(rings * sectors * 2);
        auto iter = vbl.begin();
       // std::vector<GLfloat>::iterator n = sphere_normals.begin();
       // std::vector<GLfloat>::iterator t = sphere_texcoords.begin();
        for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
                float const y = sin( -D3DX_PI / 2 + D3DX_PI * r * R );
                float const x = cos(2 * D3DX_PI * s * S) * sin( D3DX_PI * r * R );
                float const z = sin(2 * D3DX_PI * s * S) * sin( D3DX_PI * r * R );
				//float const u = asin(x) / D3DX_PI + 0.5;
				//float const v = asin(y) / D3DX_PI + 0.5;

				/*
                *t++ = s*S;
                *t++ = r*R;
				*/
                *iter++ = D3DXVECTOR3( x , y , z );

				/*
                *n++ = x;
                *n++ = y;
                *n++ = z;
				*/
        }

        ibl.resize(rings * sectors * 6);
        vector<WORD>::iterator i = ibl.begin();
        for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {

                *i++ = r * sectors + s;
                *i++ = r * sectors + (s+1);
                *i++ = (r+1) * sectors + s;

				*i++ = (r+1) * sectors + s;		
				*i++ = (r+1) * sectors + (s+1);
				*i++ = r * sectors + (s+1);
        }

	D3D11_BUFFER_DESC bd;
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( D3DXVECTOR3 ) * vbl.size();
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA InitData;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = &vbl[0];
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pVertexBuffer );

	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( WORD ) * ibl.size();
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	InitData.pSysMem = &ibl[0];
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pIndexBuffer );

	indexSize = ibl.size();

	vector<TexVertex> vb;
	/* SUN */
	vb.resize(6);
	auto it = vb.begin();

	TexVertex plane[] = 
	{
		{D3DXVECTOR3(-0.2f, 1.0f, -0.2f), D3DXVECTOR2(0.0f, 0.0f)},
		{D3DXVECTOR3( 0.2f, 1.0f, -0.2f), D3DXVECTOR2(0.5f, 0.0f)},
		{D3DXVECTOR3(-0.2f, 1.0f,  0.2f), D3DXVECTOR2(0.0f, 1.0f)},
		{D3DXVECTOR3( 0.2f, 1.0f,  0.2f), D3DXVECTOR2(0.5f, 1.0f)},
	};
	*it++ = plane[0];
	*it++ = plane[1];
	*it++ = plane[3];

	*it++ = plane[0];
	*it++ = plane[2];
	*it++ = plane[3];

	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( TexVertex ) * 6;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = &vb[0];
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pSunVertexBuffer );
	vb.clear();

	/* MOON */
	vb.resize(6);
	it = vb.begin();

	TexVertex plane2[] = 
	{
		{D3DXVECTOR3(-0.2f, 1.0f, -0.2f), D3DXVECTOR2(0.5f, 0.0f)},
		{D3DXVECTOR3( 0.2f, 1.0f, -0.2f), D3DXVECTOR2(1.0f, 0.0f)},
		{D3DXVECTOR3(-0.2f, 1.0f,  0.2f), D3DXVECTOR2(0.5f, 1.0f)},
		{D3DXVECTOR3( 0.2f, 1.0f,  0.2f), D3DXVECTOR2(1.0f, 1.0f)},
	};
	*it++ = plane2[0];
	*it++ = plane2[1];
	*it++ = plane2[3];

	*it++ = plane2[0];
	*it++ = plane2[2];
	*it++ = plane2[3];

	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( TexVertex ) * 6;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = &vb[0];
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pMoonVertexBuffer );
	vb.clear();

	/* STARS */
	
	vb.resize(6);
	it = vb.begin();

	TexVertex plane3[] = 
	{
		{D3DXVECTOR3(-0.1f, 1.0f, -0.1f), D3DXVECTOR2(0.0f, 0.0f)},
		{D3DXVECTOR3( 0.1f, 1.0f, -0.1f), D3DXVECTOR2(1.0f, 0.0f)},
		{D3DXVECTOR3(-0.1f, 1.0f,  0.1f), D3DXVECTOR2(0.0f, 1.0f)},
		{D3DXVECTOR3( 0.1f, 1.0f,  0.1f), D3DXVECTOR2(1.0f, 1.0f)},
	};
	*it++ = plane3[0];
	*it++ = plane3[1];
	*it++ = plane3[3];

	*it++ = plane3[0];
	*it++ = plane3[2];
	*it++ = plane3[3];

	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( TexVertex ) * 6;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	ZeroMemory( &InitData, sizeof(InitData) );
	InitData.pSysMem = &vb[0];
	pd3dDevice->CreateBuffer( &bd, &InitData, &m_pStarVertexBuffer );

	vector<D3DXMATRIX> mb;
	mb.resize(STARCOUNT);
	auto mit = mb.begin();

	for(r = 0; r < STARCOUNT; r++) {
		D3DXMATRIX mat, scale, rot;
		float const y = rand() / 121.0;
		float const x = rand() / 91.0;
		float const z = rand() / 97.0;
		D3DXMatrixRotationYawPitchRoll(&rot, x, y, z);
		float const s = ((sin(rand()) + 1.0) / 8.0 + 0.75) / 50.0;
		D3DXMatrixScaling(&scale, s, 1.0, s);
		D3DXMatrixMultiply(&mat, &rot, &scale);
		*mit++ = mat;

	}
	ZeroMemory( &bd, sizeof(bd) );
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( D3DXMATRIX ) * STARCOUNT;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	D3D11_SUBRESOURCE_DATA instanceData;
	instanceData.pSysMem = &mb[0];
	instanceData.SysMemPitch = 0;
	instanceData.SysMemSlicePitch = 0;
	pd3dDevice->CreateBuffer( &bd, &instanceData, &m_pStarInstanceBuffer );
	
};

float Skybox::setTime(double dTime, float* moonlight) {
	D3DXMATRIX mRotz;
	D3DXMATRIX mRoty;
	D3DXMATRIX mRotx;
	D3DXVECTOR3 Sun  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	D3DXVECTOR3 Moon = D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	D3DXMatrixRotationZ(&mRotz, dTime);
	D3DXMatrixRotationX(&mRotx, 0);
	D3DXMatrixMultiply(&m_RotSun, &mRotz, &mRotx);
	D3DXVec3Transform(&m_Sun, &Sun, &m_RotSun);

	D3DXMatrixRotationZ(&mRotz, dTime + D3DX_PI);
	D3DXMatrixRotationX(&mRotx, sin(dTime / 31.0f) / 4.2f);
	D3DXMatrixMultiply(&m_RotMoon, &mRotx, &mRotz);
	D3DXVec3Transform(&m_Moon, &Moon, &m_RotMoon);

	D3DXMatrixRotationY(&mRotz, dTime / 10.0f);
	D3DXMatrixRotationZ(&mRotx, D3DX_PI / 2.0f);
	D3DXMatrixMultiply(&m_RotStars, &mRotx, &mRotz);

	*moonlight = (D3DXVec4Dot(&m_Sun, &m_Moon) * 10.0f);

	Sun = D3DXVECTOR3(m_Sun.x, m_Sun.y, m_Sun.z);
	D3DXVECTOR3 ground = D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	float value = D3DXVec3Dot(&ground, &Sun);
	      value += 0.2f;

	return max(0.0f, min(1.0f, value));
}

void Skybox::OnD3D11ResizedSwapChain( const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc )
{
}

void Skybox::D3D11Render( CBaseCamera * cam, ID3D11DeviceContext* pd3dImmediateContext )
{
	UINT uStrides = sizeof( TexVertex  );
	UINT uOffsets = 0;

	D3DXMATRIX mView = *cam->GetViewMatrix();
	D3DXMATRIX mProj = *cam->GetProjMatrix();
	mView._41 = 0.0f; mView._42 = 0.0f; mView._43 = 0.0f;
	D3DXMATRIX mViewProj = mView * mProj;

	CB_VS_PER_FRAME				cb0;
	D3DXMatrixTranspose( &cb0.mView, &mView );
	D3DXMatrixTranspose( &cb0.mViewProjection, &mViewProj );

	CB_PS_PER_FRAME				cb1;
	cb1.cFogColor		= m_Sun;

	CB_VS_PER_OBJECT			cb2;
	D3D11_MAPPED_SUBRESOURCE	cbMapped;

	pd3dImmediateContext->UpdateSubresource( m_pcbVSPerFrame11, 0, NULL, &cb0, 0, 0 );
	pd3dImmediateContext->UpdateSubresource( m_pcbPSPerFrame11, 0, NULL, &cb1, 0, 0 );
	D3DXMatrixTranspose( &cb2.mWorld, &m_RotStars );
	if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
		CopyMemory(cbMapped.pData, &cb2, sizeof( CB_VS_PER_OBJECT ));
		pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
	}
	float BlendFactor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
	pd3dImmediateContext->OMSetBlendState(m_pBlendState11, BlendFactor, 0xffffffff);
	pd3dImmediateContext->OMSetDepthStencilState(m_pDepthStencilState11, 1);
	pd3dImmediateContext->VSSetConstantBuffers( 0, 1, &m_pcbVSPerFrame11 );
	pd3dImmediateContext->VSSetConstantBuffers( 1, 1, &m_pcbVSPerObject11 );
	pd3dImmediateContext->PSSetConstantBuffers( 0, 1, &m_pcbPSPerFrame11 );
	pd3dImmediateContext->PSSetSamplers(        0, 1, &m_pSamplerState11 );
	pd3dImmediateContext->PSSetShaderResources( 0, 1, &m_pTextureRVGlow );
	pd3dImmediateContext->PSSetShaderResources( 1, 1, &m_pTextureRVColor );
	pd3dImmediateContext->PSSetShaderResources( 2, 1, &m_pTextureRVSun );
	pd3dImmediateContext->PSSetShaderResources( 3, 1, &m_pTextureRVStar );
	pd3dImmediateContext->IASetPrimitiveTopology( D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
	
	ID3D11Buffer* bufferPointers[2];
	unsigned int strides[2];
	unsigned int offsets[2];
	bufferPointers[0] = m_pStarVertexBuffer;	
	bufferPointers[1] = m_pStarInstanceBuffer;
	strides[0] = sizeof( TexVertex );
	strides[1] = sizeof( D3DXMATRIX );
	offsets[0] = 0;
	offsets[1] = 0;
	pd3dImmediateContext->VSSetShader( m_pStarVertexShader, NULL, 0 );
	pd3dImmediateContext->PSSetShader( m_pStarPixelShader, NULL, 0 );
	pd3dImmediateContext->IASetInputLayout( m_pVertexLayoutInstanced );
	pd3dImmediateContext->IASetVertexBuffers(0, 2, bufferPointers, strides, offsets);
	pd3dImmediateContext->DrawInstanced( 6, STARCOUNT, 0, 0);

	D3DXMatrixTranspose( &cb2.mWorld, &m_RotMoon );
	if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
		CopyMemory(cbMapped.pData, &cb2, sizeof( CB_VS_PER_OBJECT ));
		pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
	}
//	pd3dImmediateContext->VSSetConstantBuffers( 1, 1, &m_pcbVSPerObject11 );
	pd3dImmediateContext->VSSetShader( m_pSunVertexShader, NULL, 0 );
	pd3dImmediateContext->PSSetShader( m_pSunPixelShader, NULL, 0 );
	pd3dImmediateContext->IASetInputLayout( m_pVertexLayoutTextured );
	pd3dImmediateContext->IASetVertexBuffers( 0, 1, &m_pMoonVertexBuffer, &uStrides, &uOffsets );
	pd3dImmediateContext->Draw( 6, 0);
	
	uStrides = sizeof( D3DXVECTOR3 );
	pd3dImmediateContext->VSSetShader( m_pSkyVertexShader, NULL, 0 );
	pd3dImmediateContext->PSSetShader( m_pSkyPixelShader, NULL, 0 );
	pd3dImmediateContext->IASetInputLayout( m_pVertexLayout );
	pd3dImmediateContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &uStrides, &uOffsets );
	pd3dImmediateContext->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
	pd3dImmediateContext->DrawIndexed( indexSize, 0, 0 );
	
	uStrides = sizeof( TexVertex );
	D3DXMatrixTranspose( &cb2.mWorld, &m_RotSun );
	if (pd3dImmediateContext->Map(m_pcbVSPerObject11, 0, D3D11_MAP_WRITE_DISCARD, 0, &cbMapped) == S_OK) {
		CopyMemory(cbMapped.pData, &cb2, sizeof( CB_VS_PER_OBJECT ));
		pd3dImmediateContext->Unmap(m_pcbVSPerObject11, 0);
	}
//	pd3dImmediateContext->VSSetConstantBuffers( 1, 1, &m_pcbVSPerObject11 );
	pd3dImmediateContext->VSSetShader( m_pSunVertexShader, NULL, 0 );
	pd3dImmediateContext->PSSetShader( m_pSunPixelShader, NULL, 0 );
	pd3dImmediateContext->IASetInputLayout( m_pVertexLayoutTextured );
	pd3dImmediateContext->IASetVertexBuffers( 0, 1, &m_pSunVertexBuffer, &uStrides, &uOffsets );
	pd3dImmediateContext->Draw( 6, 0);
	
	pd3dImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	pd3dImmediateContext->OMSetBlendState(NULL, BlendFactor, 0xffffffff);
	pd3dImmediateContext->OMSetDepthStencilState(NULL, 1);
}

void Skybox::OnD3D11ReleasingSwapChain()
{
}

void Skybox::OnD3D11DestroyDevice()
{
    m_pd3dDevice = NULL;

    SAFE_RELEASE( m_pVertexLayout );
	SAFE_RELEASE( m_pVertexLayoutTextured );
	SAFE_RELEASE( m_pVertexLayoutInstanced );

	SAFE_RELEASE( m_pVertexBuffer );
	SAFE_RELEASE( m_pIndexBuffer );

	SAFE_RELEASE (m_pSunVertexBuffer );
	SAFE_RELEASE( m_pMoonVertexBuffer );
	SAFE_RELEASE( m_pStarVertexBuffer );
	SAFE_RELEASE( m_pStarInstanceBuffer );

	SAFE_RELEASE( m_pTextureRVGlow );
	SAFE_RELEASE( m_pTextureRVColor );
	SAFE_RELEASE( m_pTextureRVSun );
	SAFE_RELEASE( m_pTextureRVStar );

	SAFE_RELEASE( m_pSkyVertexShader );
	SAFE_RELEASE( m_pSkyPixelShader );
	SAFE_RELEASE( m_pSunVertexShader );
	SAFE_RELEASE( m_pSunPixelShader );
	SAFE_RELEASE( m_pStarVertexShader );
	SAFE_RELEASE( m_pStarPixelShader );

	SAFE_RELEASE( m_pcbVSPerFrame11 );
	SAFE_RELEASE( m_pcbPSPerFrame11 );
	SAFE_RELEASE( m_pcbVSPerObject11 );

	SAFE_RELEASE( m_pSamplerState11 );
	SAFE_RELEASE( m_pBlendState11 );
	SAFE_RELEASE( m_pDepthStencilState11 );
}